package com.witmore.skyline.web.filter;

import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jk.common.utils.JwtUtil;
import com.witmore.skyline.web.config.GlobalAccountSession;
import com.witmore.skyline.web.controller.enums.WitmoreErrorCode;
import com.witmore.skyline.web.controller.vo.result.AccountSession;
import com.witmore.skyline.web.controller.vo.result.ResponseResult;
import com.witmore.skyline.web.exception.AsyncWeChatNotifier;
import com.witmore.skyline.web.exception.WitmoreException;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.SneakyThrows;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;

/**
 * Description: AccessTokenAuthenticationFilter
 * Author: 豆子高
 * Date: 2025/3/3 11:10
 */
@Component
public class AccessTokenAuthenticationFilter extends OncePerRequestFilter {

    private static final String[] EXCLUDE_URLS = {"/api/login", "/api/develop","/witmore/open/*","/actuator/health"};

    private final JwtUtil jwtUtil;

    private final AsyncWeChatNotifier asyncWeChatNotifier;

    @Autowired
    public AccessTokenAuthenticationFilter(JwtUtil jwtUtil, AsyncWeChatNotifier asyncWeChatNotifier) {
        this.jwtUtil = jwtUtil;
        this.asyncWeChatNotifier = asyncWeChatNotifier;
    }

    @SneakyThrows
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        try {
            // 1、获取请求的URI
            String requestURI = request.getRequestURI();
            if (StringUtils.containsAny(requestURI, EXCLUDE_URLS)) {
                filterChain.doFilter(request, response);
                return;
            }
            // 2、验证token
            String accessToken = request.getHeader("token");
            if (StringUtils.isEmpty(accessToken)) {
                sendErrorResponse(response, WitmoreErrorCode.UNAUTHORIZED);
                return;
            }

            String claimsStr;
            try {
                claimsStr = jwtUtil.validateToken(accessToken);
                if (StringUtils.isEmpty(claimsStr)) {
                    sendErrorResponse(response, WitmoreErrorCode.UNAUTHORIZED);
                    return;
                }
            } catch (Exception e) {
                sendErrorResponse(response, WitmoreErrorCode.UNAUTHORIZED);
                return;
            }
            AccountSession accountSession = JSONObject.parseObject(claimsStr, AccountSession.class);
            if (accountSession == null || accountSession.getId() == null) {
                sendErrorResponse(response, WitmoreErrorCode.UNAUTHORIZED);
                return;
            }
            // 3、设置用户会话信息到ThreadLocal
            GlobalAccountSession.setUserInfo(accountSession);
            // 4、执行过滤器链
            filterChain.doFilter(request, response);
        } catch (Exception e) {
            sendErrorResponse(response, e);
        } finally {
            // 清除用户会话信息
            GlobalAccountSession.removeUserInfo();
        }

    }

    private void sendErrorResponse(HttpServletResponse response, WitmoreErrorCode errorCode) throws IOException {
        sendErrorResponse(response, errorCode.getCode(), errorCode.getMessage());
    }


    private void sendErrorResponse(HttpServletResponse response, Exception e) throws IOException {
        int code = WitmoreErrorCode.SYSTEM_ERROR.getCode();
        String message = e != null ? e.getMessage() : WitmoreErrorCode.SYSTEM_ERROR.getMessage();
        if (e instanceof WitmoreException) {
            WitmoreErrorCode errorCode = ((WitmoreException) e).getErrorCode();
            code = errorCode.getCode();
            message = errorCode.getMessage();
        }
        sendErrorResponse(response, code, message);
    }

    /**
     * 发送错误响应的统一方法，带错误信息
     */
    private void sendErrorResponse(HttpServletResponse response, int errorCode, String errorMessage) throws IOException {
        response.setContentType("application/json;charset=UTF-8");
        response.setStatus(errorCode);
        // 构建统一的错误响应体
        ResponseResult<Void> responseResult = new ResponseResult<>();
        responseResult.setCode(errorCode);
        responseResult.setMessage(errorMessage);
        responseResult.setData(null);
        // 将错误响应体写入响应流
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.writeValue(response.getWriter(), responseResult);
//        asyncWeChatNotifier.sendSystemErrorToWeChatAsync(errorMessage);
    }
}
